home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / C / Applications / POV-Ray 3.0.2 / src / SOURCE / MEM.C < prev    next >
Encoding:
C/C++ Source or Header  |  1996-10-09  |  23.7 KB  |  987 lines  |  [TEXT/CWIE]

  1. /****************************************************************************
  2. *                mem.c
  3. *
  4. *  This module contains the code for our own memory allocation/deallocation,
  5. *  providing memory tracing, statistics, and garbage collection options.
  6. *
  7. *  from Persistence of Vision(tm) Ray Tracer
  8. *  Copyright 1996 Persistence of Vision Team
  9. *---------------------------------------------------------------------------
  10. *  NOTICE: This source code file is provided so that users may experiment
  11. *  with enhancements to POV-Ray and to port the software to platforms other
  12. *  than those supported by the POV-Ray Team.  There are strict rules under
  13. *  which you are permitted to use this file.  The rules are in the file
  14. *  named POVLEGAL.DOC which should be distributed with this file. If
  15. *  POVLEGAL.DOC is not available or for more info please contact the POV-Ray
  16. *  Team Coordinator by leaving a message in CompuServe's Graphics Developer's
  17. *  Forum.  The latest version of POV-Ray may be found there as well.
  18. *
  19. * This program is based on the popular DKB raytracer version 2.12.
  20. * DKBTrace was originally written by David K. Buck.
  21. * DKBTrace Ver 2.0-2.12 were written by David K. Buck & Aaron A. Collins.
  22. *
  23. *****************************************************************************/
  24.  
  25. #include "frame.h"
  26. #include "povproto.h"           /* Error() */
  27.  
  28. #include "mem.h"
  29. #include "parse.h"              /* MAError() */
  30. #include "povray.h"             /* stats[] global var */
  31.  
  32.  
  33. /************************************************************************
  34. * AUTHOR
  35. *
  36. *   Steve Anger:70714,3113
  37. *
  38. * DESCRIPTION
  39. *
  40. This module replaces the memory allocation calls malloc, calloc, realloc
  41. and free with the macros POV_MALLOC, POV_CALLOC, POV_REALLOC, and POV_FREE.
  42. These macros work the same as the standard C functions except that the
  43. POV_xALLOC functions also take a message as the last parameter and
  44. automatically call MAError(msg) if the allocation fails. That means that
  45. instead of writing
  46.  
  47.   if ((New = malloc(sizeof(*New))) == NULL)
  48.     {
  49.     MAError ("new object");
  50.     }
  51.  
  52. you'd just use
  53.  
  54.   New = POV_MALLOC (sizeof(*New), "new object");
  55.  
  56. This also expands the function of the macros to include error checking and
  57. memory tracking.
  58.  
  59. The following macros need to be defined in config.h, depending of what
  60. features the compile needs:
  61.  
  62. #define MEM_TAG     - Enables memory tag debugging
  63. --------------------------------------------------
  64. Memory tag debugging adds a 32-bit identifier to the beginning of each
  65. allocated memory block and erases it after the block has been free'd. This
  66. lets POV_FREE verify that the block it's freeing is valid and issue an
  67. error message if it isn't. Makes it easy to find those nasty double free's
  68. which usually corrupt the heap.
  69.  
  70. #define MEM_RECLAIM - Enables garbage collection
  71. ------------------------------------------------
  72. Garbage collection maintains a list of all currently allocated memory so
  73. that it can be free'd when the program exits. Normally POV-Ray will free all
  74. of its memory on its own, however abnormal exits such as parser errors or
  75. user aborts bypass the destructors. There are four functions which control
  76. the garbage collection:
  77.  
  78. mem_init()
  79.   Initializes global variables used by the garbage collection routines.
  80.   This function should be called once before any memory allocation functions
  81.   are called.
  82.  
  83. mem_mark()
  84.   Starts a new memory pool. The next call to mem_release() will only release
  85.   memory allocated after this call.
  86.  
  87. mem_release (int LogFile)
  88.   Releases all unfree'd memory allocated since the last call to mem_mark().
  89.   The LogFile parameter determines if it dumps the list of unfree'd memory to
  90.   a file.
  91.  
  92. mem_release_all (int LogFile)
  93.   Releases all unfree'd memory allocated since the program started running.
  94.  
  95. POV-Ray only uses the mem_release_all() function however mem_mark() and
  96. mem_release() might be useful for implenting a leak-free animation loop.
  97.  
  98. #define MEM_TRACE   - Enables garbage collection and memory tracing
  99. -------------------------------------------------------------------
  100. Memory tracing stores the file name and line number for ever POV_xALLOC
  101. call and dumps a list of unfree'd blocks when POV-Ray terminates.
  102.  
  103. #define MEM_STATS 1 - enables tracking of memory statistics
  104. -------------------------------------------------------------------
  105. Memory statistics enables routines that will track overall memory usage.
  106. After all memory allocation/deallocation has taken place, and before you
  107. re-initialize everything with another mem_init() call, you can call some
  108. accessor routines to determine how memory was used.  Setting MEM_STATS
  109. to 1 only tracks peak memory usage.  Setting it to 2 additionally tracks
  110. number of calls to malloc/free and some other statistics.
  111. *
  112. * CHANGES
  113. *
  114. *   Aug 1995 : Steve Anger - Creation.
  115. *   Apr 1996 : Eduard Schwan - Added MEM_STATS code
  116. *   Jul 1996 : Andreas Dilger - Force mem_header to align on double boundary
  117. **************************************************************************/
  118.  
  119.  
  120. /****************************************************************************/
  121. /* Allow user definable replacements for memory functions                   */
  122. /****************************************************************************/
  123. #ifndef MALLOC
  124. #define MALLOC malloc
  125. #endif
  126.  
  127. #ifndef CALLOC
  128. #define CALLOC calloc
  129. #endif
  130.  
  131. #ifndef REALLOC
  132. #define REALLOC realloc
  133. #endif
  134.  
  135. #ifndef FREE
  136. #define FREE free
  137. #endif
  138.  
  139.  
  140. /****************************************************************************/
  141. /* internal use                                                             */
  142. /****************************************************************************/
  143.  
  144. /* if TRACE is on, the RECLAIM must also be on */
  145. #if defined(MEM_TRACE) && !defined (MEM_RECLAIM)
  146. #define MEM_RECLAIM
  147. #endif
  148.  
  149. /* This is the filename created for memory leakage information */
  150. #if defined(MEM_TRACE)
  151. #define MEM_LOG_FNAME   "Memory.Log"
  152. #endif
  153.  
  154. /* determine if we need to add a header to our memory records */
  155. #if defined(MEM_TAG) || defined(MEM_RECLAIM) || defined(MEM_TRACE) || defined(MEM_STATS)
  156. #define MEM_HEADER
  157. #endif
  158.  
  159. #define MEMNODE struct mem_node
  160.  
  161. #if defined(MEM_HEADER)
  162.  
  163. struct mem_node
  164. {
  165.  
  166. /* We have to do lots of testing here to make sure that the size of the 
  167.  * mem_node struct is an even multiple of the sizeof(double) (usually 8
  168.  * bytes, or we royally screw up some architectures.  Yuck!!!  To make
  169.  * things easier, we have smaller groups of variables, and make them
  170.  * work out to multiples of 8 bytes, rather than trying to do it for the
  171.  * whole structure.  In most cases, only 4 bytes are wasted, as this is
  172.  * mostly for debugging anyways.
  173.  */
  174.  
  175. #if defined(MEM_TAG)
  176.   long tag;
  177. #if !defined(MEM_STATS) || defined(MEM_TRACE) 
  178.   long junk1;
  179. #endif /* !MEM_STATS */
  180. #endif /* MEM_TAG */
  181.  
  182. #if defined(MEM_STATS) && !defined(MEM_TRACE) 
  183.   size_t size;
  184. #if !defined(MEM_TAG)
  185.   long junk1;
  186. #endif /* !MEM_TAG */
  187. #endif /* MEM_STATS */
  188.  
  189. #if defined(MEM_RECLAIM)
  190.   MEMNODE *prev;
  191.   MEMNODE *next;
  192.   long poolno;
  193. #if defined(MEM_TRACE)
  194.   char *file;
  195.   long line;
  196.   size_t size;
  197. #else
  198.   long junk2;
  199. #endif /* MEM_TRACE */
  200. #endif /* MEM_RECLAIM */
  201.  
  202. };
  203. #endif /* MEM_HEADER */
  204.  
  205.  
  206. #if defined(MEM_RECLAIM)
  207. static int poolno = 0;
  208. static MEMNODE *memlist = NULL;
  209. #endif
  210.  
  211.  
  212. static int leak_msg = FALSE;
  213.  
  214.  
  215. #if defined(MEM_HEADER)
  216. #define NODESIZE ((sizeof(MEMNODE)+3)/4)*4  /* Align memory on 4 byte boundary */
  217. #else
  218. #define NODESIZE 0
  219. #endif
  220.  
  221.  
  222. #if defined(MEM_RECLAIM)
  223. static void add_node(MEMNODE * node);
  224. static void remove_node(MEMNODE * node);
  225. #endif
  226.  
  227.  
  228. #if defined(MEM_TAG)
  229. /* the tag value that marks our used memory */
  230. #define MEMTAG_VALUE   0x4D546167L
  231.  
  232. static int mem_check_tag(MEMNODE * node);
  233.  
  234. #endif
  235.  
  236.  
  237. #if defined(MEM_RECLAIM)
  238. static long num_nodes;          /* keep track of valence of node list */
  239. #endif /* MEM_RECLAIM */
  240.  
  241.  
  242. #if defined(MEM_STATS)
  243.  
  244. typedef struct MemStats_Struct MEMSTATS;
  245.  
  246. struct MemStats_Struct
  247. {
  248.   size_t   smallest_alloc;    /* smallest # of bytes in one malloc() */
  249.   size_t   largest_alloc;     /* largest # of bytes in one malloc() */
  250.   size_t   current_mem_usage; /* current total # of bytes allocated */
  251.   size_t   largest_mem_usage; /* peak total # of bytes allocated */
  252. #if (MEM_STATS>=2)
  253.   /* could add a running average size too, someday */
  254.   long int total_allocs;      /* total # of alloc calls */
  255.   long int total_frees;       /* total # of free calls */
  256.   char    *smallest_file;     /* file name of largest alloc */
  257.   int      smallest_line;     /* file line of largest alloc */
  258.   char    *largest_file;      /* file name of largest alloc */
  259.   int      largest_line;      /* file line of largest alloc */
  260. #endif
  261. };
  262.  
  263. /* keep track of memory allocation statistics */
  264. static MEMSTATS mem_stats;
  265.  
  266. /* local prototypes */
  267. static void mem_stats_init PARAMS((void));
  268. static void mem_stats_alloc PARAMS((size_t nbytes, char *file, int line));
  269. static void mem_stats_free PARAMS((size_t nbytes));
  270.  
  271. #endif
  272.  
  273.  
  274. /****************************************************************************/
  275. void mem_init()
  276. {
  277. #if defined(MEM_RECLAIM)
  278.   num_nodes = 0;
  279.   poolno = 0;
  280.   memlist = NULL;
  281. #endif
  282. #if defined(MEM_STATS)
  283.   mem_stats_init();
  284. #endif
  285.   leak_msg = FALSE;
  286. }
  287.  
  288.  
  289. #if defined(MEM_TAG)
  290. /****************************************************************************/
  291. /* return TRUE if pointer is non-null and has a valid tag */
  292. static int mem_check_tag(node)
  293. MEMNODE *node;
  294. {
  295.   int isOK = FALSE;
  296.  
  297.   if (node != NULL)
  298.     if (node->tag == MEMTAG_VALUE)
  299.       isOK = TRUE;
  300.   return isOK;
  301. }
  302.  
  303. #endif /* MEM_TAG */
  304.  
  305.  
  306. /****************************************************************************/
  307. void *pov_malloc(size, file, line, msg)
  308. size_t size;
  309. char *file;
  310. int line;
  311. char *msg;
  312. {
  313.   void *block;
  314.   size_t totalsize;
  315. #if defined(MEM_HEADER)
  316.   MEMNODE *node;
  317. #endif
  318.  
  319. #if defined(MEM_HEADER)
  320.   if (size == 0)
  321.   {
  322.     Error("Attempt to malloc zero size block (File: %s Line: %d).\n", file, line);
  323.   }
  324. #endif
  325.  
  326.   totalsize=size+NODESIZE; /* number of bytes allocated in OS */
  327.  
  328.   block = (void *)MALLOC(totalsize);
  329.  
  330.   if (block == NULL)
  331.     MAError(msg, size);
  332.  
  333. #if defined(MEM_HEADER)
  334.   node = (MEMNODE *) block;
  335. #endif
  336.  
  337. #if defined(MEM_TAG)
  338.   node->tag = MEMTAG_VALUE;
  339. #endif
  340.  
  341. #if defined(MEM_TRACE) || defined(MEM_STATS)
  342.   node->size = totalsize;
  343. #endif
  344. #if defined(MEM_TRACE)
  345.   node->file = file;
  346.   node->line = line;
  347. #endif
  348.  
  349. #if defined(MEM_RECLAIM)
  350.   add_node(node);
  351. #endif
  352.  
  353. #if defined(MEM_STATS)
  354.   mem_stats_alloc(totalsize, file, line);
  355. #endif
  356.  
  357.   return (void *)((char *)block + NODESIZE);
  358. }
  359.  
  360.  
  361. /****************************************************************************/
  362. void *pov_calloc(nitems, size, file, line, msg)
  363. size_t nitems;
  364. size_t size;
  365. char *file;
  366. int line;
  367. char *msg;
  368. {
  369.   void *block;
  370.   size_t actsize;
  371.   size_t totalsize; /* number of bytes allocated in OS */
  372. #if defined(MEM_HEADER)
  373.   MEMNODE *node;
  374. #endif
  375.  
  376.   actsize=nitems*size;
  377.   totalsize=actsize+NODESIZE;
  378.  
  379. #if defined(MEM_HEADER)
  380.   if (actsize == 0)
  381.   {
  382.     Error("Attempt to calloc zero size block (File: %s Line: %d).\n", file, line);
  383.   }
  384. #endif
  385.  
  386.   block = (void *)MALLOC(totalsize);
  387.  
  388.   if (block == NULL)
  389.     MAError(msg, actsize);
  390.  
  391.   memset(block, 0, totalsize);
  392.  
  393. #if defined(MEM_HEADER)
  394.   node = (MEMNODE *) block;
  395. #endif
  396.  
  397. #if defined(MEM_TAG)
  398.   node->tag = MEMTAG_VALUE;
  399. #endif
  400.  
  401. #if defined(MEM_TRACE) || defined(MEM_STATS)
  402.   node->size = totalsize;
  403. #endif
  404. #if defined(MEM_TRACE)
  405.   node->file = file;
  406.   node->line = line;
  407. #endif
  408.  
  409. #if defined(MEM_RECLAIM)
  410.   add_node(node);
  411. #endif
  412.  
  413. #if defined(MEM_STATS)
  414.   mem_stats_alloc(totalsize, file, line);
  415. #endif
  416.  
  417.   return (void *)((char *)block + NODESIZE);
  418. }
  419.  
  420.  
  421. /****************************************************************************/
  422. void *pov_realloc(ptr, size, file, line, msg)
  423. void *ptr;
  424. size_t size;
  425. char *file;
  426. int line;
  427. char *msg;
  428. {
  429.   void *block;
  430. #if defined(MEM_STATS)
  431.   size_t oldsize;
  432. #endif
  433.  
  434. #if defined(MEM_HEADER)
  435.   MEMNODE *node;
  436. #endif
  437.  
  438. #if defined(MEM_RECLAIM)
  439.   MEMNODE *prev;
  440.   MEMNODE *next;
  441.  
  442. #endif
  443.  
  444.   if (size == 0)
  445.   {
  446.     if (ptr)
  447.       pov_free(ptr, file, line);
  448.     return NULL;
  449.   }
  450.   else if (ptr == NULL)
  451.     return pov_malloc(size, file, line, msg);
  452.  
  453.   block = (void *)((char *)ptr - NODESIZE);
  454.  
  455. #if defined(MEM_HEADER)
  456.   node = (MEMNODE *) block;
  457. #endif
  458.  
  459. #if defined(MEM_TAG)
  460.   if (node->tag != MEMTAG_VALUE)
  461.     Error("Attempt to realloc invalid block (File: %s Line: %d).\n", file, line);
  462.  
  463.   node->tag = ~node->tag;
  464. #endif
  465.  
  466. #if defined(MEM_RECLAIM)
  467.   prev = node->prev;
  468.   next = node->next;
  469. #endif
  470.  
  471.   block = (void *)REALLOC(block, NODESIZE + size);
  472.  
  473.   if (block == NULL)
  474.     MAError(msg, size);
  475.  
  476. #if defined(MEM_STATS)
  477.   /* REALLOC does an implied FREE... */
  478.   oldsize = ((MEMNODE *)block)->size;
  479.   mem_stats_free(oldsize);
  480.   /* ...and an implied MALLOC... */
  481.   mem_stats_alloc(NODESIZE + size, file, line);
  482. #endif
  483.  
  484. #if defined(MEM_HEADER)
  485.   node = (MEMNODE *) block;
  486. #endif
  487.  
  488. #if defined(MEM_TAG)
  489.   node->tag = MEMTAG_VALUE;
  490. #endif
  491.  
  492. #if defined(MEM_TRACE) || defined(MEM_STATS)
  493.   node->size = size + NODESIZE;
  494. #endif
  495. #if defined(MEM_TRACE)
  496.   node->file = file;
  497.   node->line = line;
  498. #endif
  499.  
  500. #if defined(MEM_RECLAIM)
  501.   if (prev == NULL)
  502.     memlist = node;
  503.   else
  504.     prev->next = node;
  505.   if (node->next != NULL)
  506.     node->next->prev = node;
  507.   if (next != NULL)
  508.     next->prev = node;
  509. #endif
  510.  
  511.   return (void *)((char *)block + NODESIZE);
  512. }
  513.  
  514.  
  515. /****************************************************************************/
  516. void pov_free(ptr, file, line)
  517. void *ptr;
  518. char *file;
  519. int line;
  520. {
  521.   void *block;
  522.  
  523. #if defined(MEM_HEADER)
  524.   MEMNODE *node;
  525. #endif
  526.  
  527.   if (ptr == NULL)
  528.     Error("Attempt to free NULL pointer (File: %s Line: %d).\n", file, line);
  529.  
  530.   block = (void *)((char *)ptr - NODESIZE);
  531.  
  532. #if defined(MEM_HEADER)
  533.   node = (MEMNODE *) block;
  534. #endif
  535.  
  536. #if defined(MEM_TAG)
  537.   if (node->tag == ~MEMTAG_VALUE)
  538.   {
  539.     Warning(0.0, "Attempt to free already free'd block (File: %s Line: %d).\n", file, line);
  540.     return;
  541.   }
  542.   else if (node->tag != MEMTAG_VALUE)
  543.   {
  544.     Warning(0.0, "Attempt to free invalid block (File: %s Line: %d).\n", file, line);
  545.     return;
  546.   }
  547.  
  548. #endif
  549.  
  550. #if defined(MEM_RECLAIM)
  551.   remove_node(node);
  552. #endif
  553.  
  554. #if defined(MEM_TAG)
  555.   /* do this After remove_node, so remove_node can check validity of nodes */
  556.   node->tag = ~node->tag;
  557. #endif
  558.  
  559. #if defined(MEM_STATS)
  560.   mem_stats_free(((MEMNODE*)block)->size);
  561. #endif
  562.  
  563.   FREE(block);
  564. }
  565.  
  566.  
  567. /****************************************************************************/
  568. /* Starts a new memory pool. The next mem_release() call will
  569.    only release memory allocated after this call. */
  570. void mem_mark()
  571. {
  572. #if defined(MEM_RECLAIM)
  573.   poolno++;
  574. #endif
  575. }
  576.  
  577.  
  578. /****************************************************************************/
  579. /* Releases all unfree'd memory from current memory pool */
  580. void mem_release(LogFile)
  581. int LogFile;
  582. {
  583. #if defined(MEM_RECLAIM)
  584.   FILE *f = NULL;
  585.   MEMNODE *p, *tmp;
  586.   size_t totsize;
  587.  
  588.   p = memlist;
  589.   totsize = 0;
  590.  
  591. #if defined(MEM_TRACE)
  592.   if (LogFile)
  593.   {
  594.     if (p != NULL && (p->poolno == poolno))
  595.       f = fopen(MEM_LOG_FNAME, APPEND_FILE_STRING);
  596.   }
  597. #endif /* MEM_TRACE */
  598.  
  599.   while (p != NULL && (p->poolno == poolno))
  600.   {
  601. #if defined(MEM_TRACE)
  602.  
  603. #if defined(MEM_TAG)
  604.     if (!mem_check_tag(p))
  605.       Debug_Info("mem_release(): Memory pointer corrupt!\n");
  606. #endif /* MEM_TAG */
  607.  
  608.     totsize += (p->size-NODESIZE);
  609.     if (LogFile)
  610.     {
  611.       if (!leak_msg)
  612.       {
  613.         Debug_Info("Memory leakage detected, see file '%s' for list\n",MEM_LOG_FNAME);
  614.         leak_msg = TRUE;
  615.       }
  616.  
  617.       if (f != NULL)
  618.         fprintf(f, "File:%13s  Line:%4d  Size:%lu\n", p->file, p->line, (unsigned long)(p->size-NODESIZE));
  619.     }
  620. #endif /* MEM_TRACE */
  621.  
  622. #if defined(MEM_STATS)
  623.     mem_stats_free(p->size);
  624. #endif
  625.  
  626.     tmp = p;
  627.     p = p->next;
  628.     remove_node(tmp);
  629.     FREE(tmp);
  630.   }
  631.  
  632.   if (f != NULL)
  633.     fclose(f);
  634.  
  635.   if (totsize > 0)
  636.     Debug_Info("%lu bytes reclaimed (pool #%d)\n", totsize, poolno);
  637.  
  638.   if (poolno > 0)
  639.     poolno--;
  640.  
  641. #if defined(MEM_STATS)
  642.   /* reinitialize the stats structure for next time through */
  643.   mem_stats_init();
  644. #endif
  645.  
  646. #endif /* MEM_RECLAIM */
  647. }
  648.  
  649.  
  650. /****************************************************************************/
  651. /* Released all unfree'd memory from all pools */
  652. void mem_release_all(LogFile)
  653. int LogFile;
  654. {
  655. #if defined(MEM_RECLAIM)
  656.   FILE *f = NULL;
  657.   MEMNODE *p, *tmp;
  658.   size_t totsize;
  659.  
  660.   Status_Info("Reclaiming memory\n");
  661.  
  662.   p = memlist;
  663.   totsize = 0;
  664.  
  665. #if defined(MEM_TRACE)
  666.   if (LogFile)
  667.   {
  668.     if (p != NULL)
  669.       f = fopen(MEM_LOG_FNAME, APPEND_FILE_STRING);
  670.   }
  671. #endif
  672.  
  673.   while (p != NULL)
  674.   {
  675. #if defined(MEM_TRACE)
  676.  
  677.     #if defined(MEM_TAG)
  678.     if (!mem_check_tag(p))
  679.       Debug_Info("mem_release_all(): Memory pointer corrupt!\n");
  680.     #endif /* MEM_TAG */
  681.  
  682.     totsize += (p->size-NODESIZE);
  683.     if (LogFile)
  684.     {
  685.       if (!leak_msg)
  686.       {
  687.         Debug_Info("Memory leakage detected, see file '%s' for list\n",MEM_LOG_FNAME);
  688.         leak_msg = TRUE;
  689.       }
  690.  
  691.       if (f != NULL)
  692.         fprintf(f, "File:%13s  Line:%4d  Size:%lu\n", p->file, p->line, (unsigned long)(p->size-NODESIZE));
  693.     }
  694. #endif
  695.  
  696. #if defined(MEM_STATS)
  697.     /* This is after we have printed stats, and this may slow us down a little,      */
  698.     /* so we may want to simply re-initialize the mem-stats at the end of this loop. */
  699.     mem_stats_free(p->size);
  700. #endif
  701.  
  702.     tmp = p;
  703.     p = p->next;
  704.     remove_node(tmp);
  705.     FREE(tmp);
  706.   }
  707.  
  708.   if (f != NULL)
  709.     fclose(f);
  710.  
  711.   if (totsize > 0)
  712.     Debug_Info("\n%lu bytes reclaimed\n", totsize);
  713.  
  714.   poolno = 0;
  715. #endif
  716.  
  717. #if defined(MEM_STATS)
  718.   /* reinitialize the stats structure for next time through */
  719.   mem_stats_init();
  720. #endif
  721.  
  722. }
  723.  
  724.  
  725. /****************************************************************************/
  726. #if defined(MEM_RECLAIM)
  727. /* Adds a new node to the 'allocated' list */
  728. static void add_node(node)
  729. MEMNODE *node;
  730. {
  731.  
  732. #if defined(MEM_TAG)
  733.   if (!mem_check_tag(node))
  734.     Debug_Info("add_node(): Memory pointer corrupt!\n");
  735. #endif /* MEM_TAG */
  736.  
  737.   if (memlist == NULL)
  738.   {
  739.     memlist = node;
  740.     node->poolno = poolno;
  741.     node->prev = NULL;
  742.     node->next = NULL;
  743.     num_nodes = 0;
  744.   }
  745.   else
  746.   {
  747.     memlist->prev = node;
  748.     node->poolno = poolno;
  749.     node->prev = NULL;
  750.     node->next = memlist;
  751.     memlist = node;
  752.   }
  753.   num_nodes++;
  754. }
  755.  
  756.  
  757. /****************************************************************************/
  758. /* Detatches a node from the 'allocated' list but doesn't free it */
  759. static void remove_node(node)
  760. MEMNODE *node;
  761. {
  762.  
  763. #if defined(MEM_TAG)
  764.   if (!mem_check_tag(node))
  765.     Debug_Info("remove_node(): Memory pointer corrupt!\n");
  766. #endif /* MEM_TAG */
  767.  
  768.   num_nodes--;
  769.   if (node->prev != NULL)
  770.     node->prev->next = node->next;
  771.  
  772.   if (node->next != NULL)
  773.     node->next->prev = node->prev;
  774.  
  775.   if (memlist == node)
  776.   {
  777. #if defined(MEM_TAG)
  778.     /* check node->next if it is non-null, to insure it is safe to assign. */
  779.     /* if it is null, it is safe since it is the last in the list. */
  780.     if (node->next)
  781.       if (!mem_check_tag(node->next))
  782.         Debug_Info("remove_node(): memlist pointer corrupt!\n");
  783. #endif /* MEM_TAG */
  784.  
  785.     memlist = node->next;
  786.   }
  787.  
  788. }
  789.  
  790. #endif /* MEM_RECLAIM */
  791.  
  792.  
  793. /****************************************************************************/
  794. /* A memmove routine for those systems that don't have one                  */
  795. /****************************************************************************/
  796.  
  797. void *pov_memmove (dest, src, length)
  798. void *dest, *src;
  799. size_t length;
  800. {
  801.   char *csrc =(char *)src;
  802.   char *cdest=(char *)dest;
  803.   
  804.   if (csrc < cdest && csrc + length >= cdest)
  805.   {
  806.     size_t size = cdest - csrc;
  807.  
  808.     while (length > 0)
  809.     {
  810.       memcpy(cdest + length - size, csrc + length - size, size);
  811.  
  812.       length -= size;
  813.  
  814.       if (length < size)
  815.         size = length;
  816.     }
  817.   }
  818.   /* I'm not sure if this is needed, but my docs on memcpy say the regions
  819.    * can't overlap, so theoretically we need to special case this.  If you
  820.    * don't think it's necessary, you can just comment this part out.
  821.    */
  822.   else if (cdest < csrc && cdest + length >= csrc)
  823.   {
  824.     char *new_dest = cdest;
  825.     size_t size = csrc - cdest;
  826.  
  827.     while (length > 0)
  828.     {
  829.       memcpy(new_dest, csrc, length);
  830.  
  831.       new_dest += size;
  832.       csrc += size;
  833.       length -= size;
  834.  
  835.       if (length < size)
  836.         size = length;
  837.     }
  838.   }
  839.   else
  840.   {
  841.     memcpy(cdest, csrc, length);
  842.   }
  843.  
  844.   return cdest;
  845. }
  846.  
  847.  
  848. /****************************************************************************/
  849. /* Memory Statistics gathering routines                                     */
  850. /****************************************************************************/
  851.  
  852. #if defined(MEM_STATS)
  853.  
  854. /****************************************************************************/
  855. static void mem_stats_init()
  856. {
  857.   mem_stats.smallest_alloc    = 65535;  /* Must be an unsigned number */
  858.   mem_stats.largest_alloc     = 0;
  859.   mem_stats.current_mem_usage = 0;
  860.   mem_stats.largest_mem_usage = 0;
  861. #if (MEM_STATS>=2)
  862.   mem_stats.total_allocs      = 0;
  863.   mem_stats.total_frees       = 0;
  864.   mem_stats.largest_file      = "none";
  865.   mem_stats.largest_line      = -1;
  866.   mem_stats.smallest_file     = "none";
  867.   mem_stats.smallest_line     = -1;
  868. #endif
  869. }
  870.  
  871. /****************************************************************************/
  872. /* update appropriate fields when an allocation takes place                 */
  873. static void mem_stats_alloc(nbytes, file, line)
  874. size_t nbytes;
  875. char *file;
  876. int line;
  877. {
  878.   /* update the fields */
  879.   if ((mem_stats.smallest_alloc<0) || (nbytes<mem_stats.smallest_alloc))
  880.   {
  881.     mem_stats.smallest_alloc = nbytes;
  882. #if (MEM_STATS>=2)
  883.     mem_stats.smallest_file = file;
  884.     mem_stats.smallest_line = line;
  885. #endif
  886.   }
  887.  
  888.   if (nbytes>mem_stats.largest_alloc)
  889.   {
  890.     mem_stats.largest_alloc = nbytes;
  891. #if (MEM_STATS>=2)
  892.     mem_stats.largest_file = file;
  893.     mem_stats.largest_line = line;
  894. #endif
  895.   }
  896.  
  897. #if (MEM_STATS>=2)
  898.   mem_stats.total_allocs++;
  899. #endif
  900.  
  901.   mem_stats.current_mem_usage += nbytes;
  902.  
  903.   if (mem_stats.current_mem_usage>mem_stats.largest_mem_usage)
  904.   {
  905.     mem_stats.largest_mem_usage = mem_stats.current_mem_usage;
  906.   }
  907.  
  908. }
  909.  
  910. /****************************************************************************/
  911. /* update appropriate fields when a free takes place                        */
  912. static void mem_stats_free(nbytes)
  913. size_t nbytes;
  914. {
  915.   /* update the fields */
  916.   mem_stats.current_mem_usage -= nbytes;
  917. #if (MEM_STATS>=2)
  918.   mem_stats.total_frees++;
  919. #endif
  920. }
  921.  
  922. /****************************************************************************/
  923. /* Level 1                                                                  */
  924.  
  925. /****************************************************************************/
  926. size_t mem_stats_smallest_alloc()
  927. {
  928.   return mem_stats.smallest_alloc;
  929. }
  930. /****************************************************************************/
  931. size_t mem_stats_largest_alloc()
  932. {
  933.   return mem_stats.largest_alloc;
  934. }
  935. /****************************************************************************/
  936. size_t mem_stats_current_mem_usage()
  937. {
  938.   return mem_stats.current_mem_usage;
  939. }
  940. /****************************************************************************/
  941. size_t mem_stats_largest_mem_usage()
  942. {
  943.   return mem_stats.largest_mem_usage;
  944. }
  945.  
  946. /****************************************************************************/
  947. /* Level 2                                                                  */
  948.  
  949. #if (MEM_STATS>=2)
  950.  
  951. /****************************************************************************/
  952. char *mem_stats_smallest_file()
  953. {
  954.   return mem_stats.smallest_file;
  955. }
  956. /****************************************************************************/
  957. int mem_stats_smallest_line()
  958. {
  959.   return mem_stats.smallest_line;
  960. }
  961. /****************************************************************************/
  962. char *mem_stats_largest_file()
  963. {
  964.   return mem_stats.largest_file;
  965. }
  966. /****************************************************************************/
  967. int mem_stats_largest_line()
  968. {
  969.   return mem_stats.largest_line;
  970. }
  971. /****************************************************************************/
  972. long int mem_stats_total_allocs()
  973. {
  974.   return mem_stats.total_allocs;
  975. }
  976. /****************************************************************************/
  977. long int mem_stats_total_frees()
  978. {
  979.   return mem_stats.total_frees;
  980. }
  981.  
  982. #endif
  983.  
  984. #endif /* MEM_STATS */
  985.  
  986.  
  987.